home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 June / ccd0605.iso / Software / Freeware / Programare / highlight / highlight-W32GUI-2.2-10b-Setup.exe / {app} / src / dirstream.h < prev    next >
C/C++ Source or Header  |  2004-02-01  |  11KB  |  371 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. //    file        :    dirstream.h
  3. //  copyright    :    (C) 2002 by Benjamin Kaufmann
  4. //  email        :    hume@c-plusplus.de
  5. //    internet    :    http://bens.c-plusplus.info/
  6. //
  7. //     Eine Klasse die das Browsen durch Verzeichnisse erlaubt. Dank des
  8. //     Stream-Interface ist die Klasse intuitiv bedienbar. Neben der eigentlichen
  9. //     Stream-Klasse enth∩┐╜t diese Datei au∩┐╜rdem noch einen DirStream-Iterator.
  10. //     Durch diesen Input-Iterator knnen DirStream-Objekte mit den Algorithmen
  11. //     der C++ Standardbibliothek verbunden werden.
  12. //
  13. //    Die Klasse ist so konzipiert, dass sie auf verschiedenen Platformen
  14. //     eingesetzt werden kann. Fr das tats∩┐╜hliche Browsing werden unter POSIX-
  15. //    kompatiblen Systemen die Funktionen opendir, readdir und closedir verwendet.
  16. //
  17. //    Auf Win32-Platformen verwendet diese Klasse Wrapper-Funktionen
  18. //    von Kevlin Henney. Dieser Wrapper basieren auf den den Funktionen _findfirst,
  19. //    _findnext und _findclose.
  20. //    http://www.two-sdg.demon.co.uk/curbralan/code/dirent/dirent.html
  21. //
  22. //    Die ursprngliche Idee fr diesen DirStream stammt aus dem Artikel
  23. //     "Promoting Polymorphism" von Kevlin Henney.
  24. //     http://www.appdevadvisor.co.uk/Downloads/ada5_8/Henney5_8.pdf
  25. //
  26. /////////////////////////////////////////////////////////////////////////////
  27. //
  28. /****************************************************************************
  29.  *                                                                             *
  30.  *    This program is free software; you can redistribute it and/or modify      *
  31.  *    it under the terms of the GNU General Public License as published by      *
  32.  *    the Free Software Foundation; either version 2 of the License, or         *
  33.  *    (at your option) any later version.                                       *
  34.  *                                                                            *
  35.  *     This program is distributed in the hope that it will be useful,            *
  36.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of            *
  37.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
  38.  *    GNU General Public License for more details.                               *
  39.  *                                                                            *
  40.  ****************************************************************************/
  41.  
  42. #ifndef DIR_STREAM__H_INCLUDED 
  43. #define DIR_STREAM__H_INCLUDED 
  44.  
  45. #ifdef _MSC_VER
  46. #    define for if(0);else for
  47. #    pragma warning(disable:4786)
  48. #     define HAS_STD_ITERATOR
  49. #endif
  50.  
  51. #include <string>
  52. #include <iterator>
  53. #include <algorithm>
  54. #include <cctype>
  55.  
  56. namespace DIRSTREAM
  57. {
  58.     struct AllDirs
  59.     {
  60.         bool operator() (const char*) {return true;}
  61.         
  62.     };
  63.     
  64.     struct AllFiles
  65.     {
  66.         bool operator() (const char*, bool) {return true;}
  67.         
  68.     };
  69.  
  70.     template <class F, class D> class DirStreamImpl;    // Implementationsklasse
  71.  
  72.         
  73.     template 
  74.     <
  75.         class FileSelect,            // Wird fr jede Datei aufgerufen.
  76.         class DirSelect = AllDirs    // Wird fr jede Datei aufgerufen.
  77.     >
  78.     class DirStream_t
  79.     {
  80.         public:
  81.             
  82.             /**
  83.              * Konstruktor der Klasse.
  84.              * Erstellt ein neues DirStream-Objekt.
  85.              * @param    DirName        Name des zu durchwandernden Verzeichnisses
  86.              * @param    Recurse        Unterverzeichnisse bercksichtigen ja/nein
  87.              * @param    FSelect        Funktion(sobjekt) das fr jede Datei aufgerufen wird.
  88.              *                        Liefert die Funktion false, wird der Eintrag ignoriert.
  89.              * @param    DSelect        Funktion(sobjekt) das fr jedes Unterverzeichnis 
  90.              *                        aufgerufen wird. Liefert die Funktion false, 
  91.              *                         wird der Eintrag ignoriert.
  92.              **/
  93.             explicit DirStream_t        (const char* DirName, bool Recurse = false,
  94.                                          const FileSelect& FSelect = FileSelect(),
  95.                                          const DirSelect&  DSelect = DirSelect()
  96.                                          );
  97.             
  98.             /**
  99.              * Destruktor der Klasse. 
  100.              * Gibt verwendete Resourcen frei.
  101.              **/
  102.             ~DirStream_t                ();
  103.  
  104.             /**
  105.              * Durch diesen Operator kann ein Stream-Objekt in einen void-Pointer
  106.              * umgewandelt werden. Dieser kann dann gegen NULL geprft werden.
  107.              * Dadurch werden also Ausdrcke wie if (Stream) mglich.
  108.              **/
  109.             operator const void*        () const;
  110.             
  111.             /**
  112.              * ∩┐╜er diesen Operator wird der n∩┐╜hste Eintrag des Verzeichnisses
  113.              * eingelesen. 
  114.              * @param    Name    Bezeichnung des aktuellen Verzeichniseintrags.
  115.              * @pre        Ein Verzeichnis wurde geffnet.
  116.              * @post    Name enth∩┐╜t den aktuellen Verzeichniseintrag. Existiert
  117.              *            kein solche Eintrag, liefert der Vergleich *this == 0 
  118.              *            true und der Wert von Name ist undefiniert.
  119.              **/
  120.             DirStream_t& operator >>    (std::string& Name);
  121.             
  122.             /**
  123.              * ∩┐╜fnet das Verzeichnis mit dem Namen DirName und macht damit
  124.              * ein erneutes browsing mglich. 
  125.              * @see DirStream_t
  126.              **/
  127.             bool open            (const char* DirName, bool Recurse = false, 
  128.                                  const FileSelect&    FSelect = FileSelect(),
  129.                                  const DirSelect&    DSelect    = DirSelect()
  130.                                  );
  131.  
  132.             
  133.             /// Liefert true, falls ein Verzeichnis erfolgreich geffnet wurde.
  134.             bool is_open        ()    const;
  135.             
  136.             /**
  137.              * Liefert true, falls der aktuelle Verzeichniseintrag ein Verzeichnis ist.
  138.              * @pre    IsOpen liefert true
  139.              * @post    Beantwortet die Frage, ob der aktuelle Eintrag ein Verzeichnis ist.
  140.              **/
  141.             bool directory        ()    const;
  142.         
  143.         private:
  144.             // Streamobjekte knnen nicht kopiert werden, da diese
  145.             // Operation keinen Sinn macht.
  146.             DirStream_t(const DirStream_t&);
  147.             DirStream_t& operator=(const DirStream_t&);
  148.             
  149.             DirStreamImpl<FileSelect, DirSelect>*    m_pImpl;
  150.     };
  151.  
  152.  
  153.     /**
  154.      * @class    DirStream_tIterator
  155.      * @brief    Iterator-Klasse fr DirStream_t-Objekte. 
  156.      * 
  157.      * Dieser Iterator der Kategorie-Input-Iterator ermglicht die 
  158.      * Verbindung von DirStream-Objekten mit den Algorithmen der 
  159.      * Standardbibliothek.
  160.      **/
  161.     template <class FS, class DS  = AllDirs>
  162.     class DirStream_tIterator
  163.     #ifdef HAS_STD_ITERATOR
  164.         : public std::iterator<std::input_iterator_tag, std::string>
  165.     #endif
  166.     {
  167.         // Wer std::iterator nicht hat, muss selbst fr die bentigten
  168.         // typedefs sorgen.
  169.         #ifndef HAS_STD_ITERATOR
  170.         typedef std::input_iterator_tag     iterator_category;
  171.           typedef std::string                    value_type;
  172.           typedef ptrdiff_t                     difference_type;
  173.           typedef std::string*                   pointer;
  174.           typedef std::string&                 reference;
  175.           #endif
  176.         public:
  177.             /// Der Standard-Ctor erstellt einen Ende-Iterator.
  178.             DirStream_tIterator() : m_Stream(0){}
  179.  
  180.             /**
  181.              * Dieser Ctor erstellt einen Iterator mit dem durch ein Verzeichnis
  182.              * iteriert werden kann. Ein solcher Iterator sollte immer gegen einen
  183.              * Ende-Iterator getestet werden.
  184.              **/
  185.             explicit DirStream_tIterator(DirStream_t<FS, DS>& Dir) : m_Stream(&Dir)
  186.             {
  187.                 *m_Stream >> m_CurrFile;
  188.             }
  189.  
  190.             // Implementation des Interface eines Input-Iterators
  191.  
  192.             const std::string& operator*() const
  193.             {
  194.                 return m_CurrFile;
  195.             }
  196.  
  197.             const std::string* operator->() const
  198.             {
  199.                 return &m_CurrFile;
  200.             }
  201.  
  202.             DirStream_tIterator& operator++()
  203.             {
  204.                 if(m_Stream) *m_Stream >> m_CurrFile;
  205.                 return *this;
  206.             }
  207.  
  208.             DirStream_tIterator operator++(int)
  209.             {
  210.                 DirStream_tIterator Ret = *this;
  211.                 ++*this;
  212.                 return Ret;
  213.             }
  214.  
  215.             /**
  216.              * Dieser Vergleichsoperator eigent sich nicht zum Vergleich zweier
  217.              * beliebiger DirStream_tIteratoren. Vielmehr soll mit ihm lediglich
  218.              * ein Vergleich mit einem Ende-Iterator durchgefhrt werden.
  219.              **/
  220.             bool operator==(const DirStream_tIterator& rhs) const
  221.             {
  222.                 return IsEnd () && rhs.IsEnd();
  223.             }
  224.  
  225.             /**
  226.              * @see operator==
  227.              **/
  228.             bool operator!=(const DirStream_tIterator& rhs) const
  229.             {
  230.                 return !IsEnd()||!rhs.IsEnd();
  231.             }
  232.  
  233.         private:
  234.             bool IsEnd() const
  235.             {
  236.                 return !m_Stream ||!*m_Stream;
  237.             }
  238.  
  239.             std::string             m_CurrFile;
  240.             DirStream_t<FS, DS>*    m_Stream;
  241.     };
  242. }
  243.  
  244. #include "dirstreamimpl.inl"    // <- Implementationsdatei
  245.  
  246. // typedefs und ntzliche Funkionsobjekte
  247. namespace DIRSTREAM
  248. {
  249.  
  250.     struct NoCurNoParent
  251.     {
  252.         bool operator() (const char* Name, bool)
  253.         {
  254.             std::string Temp(Name);
  255.             return Temp != "." && Temp != "..";
  256.         }
  257.     };
  258.     
  259.     struct SelectOnlyDirs
  260.     {
  261.         bool operator() (const char* Name, bool IsDir)
  262.         {
  263.             return IsDir && strcmp(Name, ".") && strcmp(Name, "..");
  264.         }
  265.     };
  266.     
  267.     // Dieses Funktionsobjekt w∩┐╜lt nur Eintr∩┐╜e eines Verzeichnisses aus,
  268.     // die dem Parameter Pattern entsprechen.
  269.     // Untersttzte Wildcards: * und ?
  270.     // * : 0 oder beliebig viele Zeichen
  271.     // ? : genau ein Zeichen
  272.     struct FileSelector
  273.     {
  274.         FileSelector(const char* Pattern, bool IgnoreCase = false) :
  275.             m_Pattern(Pattern), m_IgnoreCase(IgnoreCase), 
  276.             m_HasWildCard1(false), m_HasWildCard2(false)
  277.         {
  278.             if (m_IgnoreCase)
  279.             {
  280.                 #ifdef _MSC_VER
  281.                 std::transform(m_Pattern.begin(), m_Pattern.end(), m_Pattern.begin(), tolower);    
  282.                 #else
  283.                 std::transform(m_Pattern.begin(), m_Pattern.end(), m_Pattern.begin(), 
  284.                                         /*std::*/tolower);
  285.                                 #endif            
  286.                         }
  287.             if (m_Pattern.find('*') != std::string::npos) m_HasWildCard1 = true;
  288.             if (m_Pattern.find('?') != std::string::npos) m_HasWildCard2 = true;
  289.         }
  290.  
  291.         bool operator() (const char* FN, bool)
  292.         {
  293.             std::string FileName(FN);
  294.             if (m_Pattern.empty() || FileName.empty()) return false;
  295.  
  296.             std::string::size_type PattSize = m_Pattern.length();
  297.             std::string::size_type FileNameSize = FileName.length();
  298.             std::string::size_type FileRun = 0;
  299.             std::string::size_type PattRun = 0;
  300.             if (!m_HasWildCard1 && PattSize != FileNameSize) return false;
  301.             
  302.             if (m_IgnoreCase)
  303.             {
  304.             #ifdef _MSC_VER
  305.                 std::transform(FileName.begin(), FileName.end(), FileName.begin(), tolower);
  306.             #else
  307.                 std::transform(FileName.begin(), FileName.end(), FileName.begin(), /*std::*/tolower);
  308.             #endif
  309.             }
  310.             if (!m_HasWildCard1 && !m_HasWildCard2) return m_Pattern == FileName;
  311.             
  312.             bool LastIsStar = (*m_Pattern.rbegin() == '*') ? true : false;
  313.  
  314.             while (PattRun < PattSize && FileRun < FileNameSize)
  315.             {
  316.                 if (m_Pattern[PattRun] == '*')
  317.                 {    // * bedeutet 0 oder beliebig viele Zeichen.
  318.                     // Es wird jetzt das n∩┐╜hste relevante Zeichen von
  319.                     // Pattern gesucht. Danach wird geprft, ob FileName
  320.                     // dieses Zeichen enth∩┐╜t.
  321.                     PattRun = m_Pattern.find_first_not_of("*?", PattRun);
  322.  
  323.                     // Nach dem Stern folgt kein weiteres relevantes Zeichen
  324.                     // FileName passt also auf jeden Fall in das Pattern.
  325.                     if (PattRun == std::string::npos) return true;
  326.             
  327.                     char NextChar = m_Pattern[PattRun];
  328.             
  329.                     FileRun = FileName.find(NextChar, FileRun);
  330.                     // FileName enth∩┐╜t das n∩┐╜hste relevante Zeichen von
  331.                     // Pattern nicht. Demzufolge wollen wir diesen Eintrag
  332.                     // nicht.
  333.                     if (FileRun == std::string::npos) return false;
  334.                 }
  335.                 if (m_Pattern[PattRun] == '?')
  336.                 {    // ? bedeutet genau ein Zeichen. Also wird auch genau ein
  337.                     // Zeichen ignoriert.
  338.                     ++PattRun;
  339.                     ++FileRun;
  340.                     continue;
  341.                 }
  342.                 
  343.                 if (m_Pattern[PattRun++] != FileName[FileRun++]) return false;
  344.             }
  345.     
  346.             // Pattern und Filename waren bis auf das letzte Zeichen gleich.
  347.             // Da das letzte Zeichen von Pattern aber ein * ist und dieses
  348.             // ja auch fr 0 Zeichen steht, liefere true.
  349.             if (PattRun < PattSize && FileRun == FileNameSize && LastIsStar) return true;
  350.  
  351.             // FileName und Pattern stimmen nur ber ein, wenn alle Zeichen
  352.             // verglichen wurden.
  353.             return (PattRun == PattSize && FileRun == FileNameSize);
  354.         }
  355.  
  356.         private:
  357.             std::string m_Pattern;
  358.             bool         m_IgnoreCase;
  359.             bool        m_HasWildCard1;
  360.             bool        m_HasWildCard2;
  361.     
  362.     };
  363.  
  364.     // und noch zwei typedefs fr die Bequemlichkeit
  365.     typedef DirStream_t<NoCurNoParent, AllDirs> DirStream;
  366.     typedef DirStream_tIterator<NoCurNoParent, AllDirs> DirStreamIterator;
  367. }
  368.  
  369.  
  370. #endif
  371.